///////////////////////////////////////////////////////////////////////////////////////////////////
/// \file formic/wfn/data.h
///
/// \brief   header file for the wavefunction data class
///
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef FORMIC_WFN_DATA_HEADER
#define FORMIC_WFN_DATA_HEADER

#include<vector>
#include<string>
#include<complex>

//#include<formic/wfn_commands.h>
//#include<formic/mpi/interface.h>

namespace formic {

  class Archive;

//  /// \brief  function to write an object to text with leading and trailing whitespace
//  template <class T> inline void text_writeout(std::stringstream & ss, const T & val) {
//    ss << " " << val << " " << std::endl;
//  }
//  inline void text_writeout(std::stringstream & ss, const double & val) {
//    ss << " " << std::setprecision(15) << std::scientific << val << " " << std::endl;
//  }
//  inline void text_writeout(std::stringstream & ss, const std::complex<double> & val) {
//    ss << " " << std::setprecision(15) << std::scientific << val << " " << std::endl;
//  }

  ///////////////////////////////////////////////////////////////////////////////////////////////////
  /// \brief   Class to hold wavefunction data.
  ///
  /// This class holds the raw data used to define the wavefunction, which may be considered
  /// variable or fixed.  In addition, objects of this class store the position of their data
  /// in the global ordering of wavefunction variables and constants.
  ///
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  template<class S> class WfnData {

    private:

      /// \brief  a name for this data object
      std::string _name;

      /// \brief  whether the data is fixed or variable
      bool _fixed;

      /// \brief  the data
      std::vector<S> _data_vec;

//      /// \brief  position of the data in the global ordering of wavefunction data.
//      ///         Positions >= 0 indicate varaible data, while positions < 0 indicate constant data.
//      int _data_pos;

      /// \brief  assignment operator is disabled
      WfnData & operator=(const WfnData &);

      /// \brief  copy constructor is disabled
      WfnData(const WfnData &);

      /// \brief  returns the command name for creating integer wavefunction data
      static std::string command_name(int x) { return "WfnIntData"; }

      /// \brief  returns the command name for creating real wavefunction data
      static std::string command_name(double x) { return "WfnRealData"; }

      /// \brief  returns the command name for creating complex wavefunction data
      static std::string command_name(std::complex<double> x) { return "WfnComplexData"; }

    public:

      WfnData(formic::Archive & arch);

      WfnData(const std::string & name, const bool fixed, const int size, const S val);

      ///////////////////////////////////////////////////////////////////////////////////////////////////
      /// \brief returns the name of the data object
      ///
      ///////////////////////////////////////////////////////////////////////////////////////////////////
      const std::string & name() const { return this->_name; }

      ///////////////////////////////////////////////////////////////////////////////////////////////////
      /// \brief returns whether the data is fixed or variable
      ///
      ///////////////////////////////////////////////////////////////////////////////////////////////////
      bool fixed() const { return this->_fixed; }

//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief returns the position of the data in the overall data ordering
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      int data_pos() const { return this->_data_pos; }

      ///////////////////////////////////////////////////////////////////////////////////////////////////
      /// \brief returns the data as a constant reference
      ///
      ///////////////////////////////////////////////////////////////////////////////////////////////////
      const std::vector<S> & data_vec() const { return this->_data_vec; }

      ///////////////////////////////////////////////////////////////////////////////////////////////////
      /// \brief returns the data by reference
      ///
      ///////////////////////////////////////////////////////////////////////////////////////////////////
      std::vector<S> & data_vec() { return this->_data_vec; }

      ///////////////////////////////////////////////////////////////////////////////////////////////////
      /// \brief returns the size of the data vector
      ///
      ///////////////////////////////////////////////////////////////////////////////////////////////////
      size_t size() const { return this->_data_vec.size(); }

//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      /// \brief sets the position of the data in the global data ordering
//      ///
//      /// \param[in]      pos   the position of the data elements in the global ordering
//      ///
//      ///////////////////////////////////////////////////////////////////////////////////////////////////
//      void set_pos(const int pos) { _data_pos = pos; }

      void to_command(formic::Archive & arch) const;

  };

}

template<class S>
inline formic::Archive & operator<<(formic::Archive & arch, const formic::WfnData<S> & w) { w.to_command(arch); return arch; }

#endif
